# Copyright (c) 2019 Presto Labs Pte. Ltd.
# Author: xguo

import ujson as json

from coin.base.datetime_util import to_datetime
from coin.base.book.types import TradeSide, create_market_trade_event
from coin.base.book.util import pretty_book, human_readable_timestamp_record
from coin.exchange.base.ws.handler import WebsocketHandler
from coin.exchange.kraken_futures.book_builder import BookBuilder
from coin.exchange.kraken_futures.kr_rest.futures_product import KrakenFuturesProduct


class KrakenFuturesHandler(WebsocketHandler):
  def __init__(self, *, event_dist=None, feed_checker_config=None):
    super().__init__(event_dist=event_dist, feed_checker_config=feed_checker_config)

  def _debug_print(self, bids, asks):
    self._logger.info('\nbids: %s\n asks: %s',
                      json.dumps(bids, indent=2),
                      json.dumps(asks, indent=2))

  def on_depth(self, record, queue_data, topic_data):
    data = record.data
    if not isinstance(data, dict) and not isinstance(data, list):
      data = json.loads(data.tobytes())

    if 'event' in data:
      # TODO: add extra event handling
      return

    native_symbol = data['product_id']
    if not self.is_subscribed('book', native_symbol):
      return

    product = KrakenFuturesProduct.FromStrNativeProduct(native_symbol)
    if product is None:
      self._logger.error('Book data comes earlier than subscription response!')
      return

    book = None
    if data['feed'] == 'book_snapshot':
      if native_symbol not in self._books:
        book = BookBuilder(native_symbol, book_builder_observer=self._book_builder_observer)
        self._books[native_symbol] = book
      else:
        book = self._books[native_symbol]
        book.clear_book()
      book.update_timestamp(record.timestamp)
      book.snapshot(data['bids'], data['asks'])
      book.update_topic_id(record.topic_id)
      self.ready = True
    elif data['feed'] == 'book':
      if product.native_symbol not in self._books:
        # Ignore book updates coming before snapshot.
        self._logger.error('%s Book delta comes earlier than snapshot!',
                           to_datetime(record.timestamp))
        return
      book = self._books[product.native_symbol]
      book.update_timestamp(record.timestamp)
      if data['side'] == 'buy':
        if data['qty'] > 0:
          book._insert_bid(data['price'], data['qty'])
        else:
          book._delete_bid(data['price'])
      elif data['side'] == 'sell':
        if data['qty'] > 0:
          book._insert_ask(data['price'], data['qty'])
        else:
          book._delete_ask(data['price'])
      else:
        pass
    else:
      return

    if self._feed_checker:
      self._feed_checker.on_book(product=book.product, book=book, timestamp=record.timestamp)
    self.publish_event('book', book.symbol, book)

  def on_trade(self, record, queue_data, topic_data):
    data = record.data
    if not isinstance(data, dict) and not isinstance(data, list):
      data = json.loads(data.tobytes())

    if 'event' in data:
      # TODO: add extra event handling
      return

    native_symbol = data['product_id']
    if not self.is_subscribed('trade', native_symbol):
      return

    product = KrakenFuturesProduct.FromStrNativeProduct(native_symbol)
    if product is None:
      self._logger.error('Book data comes earlier than subscription response!')
      return

    trade = None
    if data['feed'] == 'trade_snapshot':
      return
    elif data['feed'] == 'trade':
      price = float(data['price'])
      qty = float(data['qty'])
      side = data['side']
      if side == 'buy':
        side = TradeSide.TRADE_BUY_SIDE
      elif side == 'sell':
        side = TradeSide.TRADE_SELL_SIDE
      else:
        raise ValueError('Unknown side: %s', data)
      trade_event = create_market_trade_event(record.timestamp,
                                              native_symbol,
                                              price,
                                              qty,
                                              side,
                                              topic_id=record.topic_id)
    else:
      return

    if self._feed_checker:
      self._feed_checker.on_trade(product=product,
                                  trade_event=trade_event,
                                  timestamp=record.timestamp)
    self.publish_event('trade', native_symbol, trade_event)
